#!/usr/bin/env python3

r"""
Exports issues from a list of repositories to individual CSV files.
Uses basic authentication (GitHub username + password) to retrieve issues
from a repository that username has access to. Supports GitHub API v3.
"""
import argparse
import csv
import getpass

import requests

auth = None
states = "all"


def write_issues(response, csv_out):
    r"""
    Parses JSON response and writes to CSV.
    """
    print(response)
    if response.status_code != 200:
        raise Exception(response.status_code)
    for issue in response.json():
        if "pull_request" not in issue:
            labels = ", ".join([label["name"] for label in issue["labels"]])

            # Below lines to overcome "TypeError: 'NoneType' object has
            # no attribute '__getitem__'"

            close_date = issue.get("closed_at")
            if close_date:
                close_date = issue.get("closed_at").split("T")[0]

            assignee_resp = issue.get("assignees", "Not Assigned")
            if assignee_resp:
                owners = ",".join(
                    [
                        assignee_login["login"]
                        for assignee_login in assignee_resp
                    ]
                )
            else:
                owners = "Not Assigned"

            milestone_resp = issue.get("milestone", "Not Assigned")
            if milestone_resp:
                milestone_resp = milestone_resp["title"].encode("utf-8")

            # Change the following line to write out additional fields
            csv_out.writerow(
                [
                    labels.encode("utf-8"),
                    issue.get("title").encode("utf-8"),
                    issue.get("state").encode("utf-8"),
                    issue.get("created_at").split("T")[0],
                    close_date,
                    issue.get("html_url").encode("utf-8"),
                    issue.get("user").get("login").encode("utf-8"),
                    owners,
                    milestone_resp,
                ]
            )


def get_issues_from_github_to_csv(name, response):
    r"""
    Requests issues from GitHub API and writes to CSV file.
    Description of argument(s):
    name  Name of the GitHub repository
    response  GitHub repository response
    """
    print(name)
    print(states)

    # Multiple requests are required if response is paged
    if "link" in response.headers:
        pages = {
            rel[6:-1]: url[url.index("<") + 1 : -1]
            for url, rel in (
                link.split(";") for link in response.headers["link"].split(",")
            )
        }
        while "last" in pages and "next" in pages:
            pages = {
                rel[6:-1]: url[url.index("<") + 1 : -1]
                for url, rel in (
                    link.split(";")
                    for link in response.headers["link"].split(",")
                )
            }
            response = requests.get(pages["next"], auth=auth)
            write_issues(response, csv_out)
            if pages["next"] == pages["last"]:
                break


parser = argparse.ArgumentParser(
    description="Write GitHub repository issues to CSV file."
)

parser.add_argument(
    "username", nargs="?", help="GitHub user name, formatted as 'username'"
)

parser.add_argument(
    "repositories",
    nargs="+",
    help="Repository names, formatted as 'basereponame/repo'",
)

parser.add_argument(
    "--all", action="store_true", help="Returns both open and closed issues."
)

args = parser.parse_args()

if args.all:
    state = "all"

username = args.username

password = getpass.getpass("Enter your GitHub Password:")

auth = (username, password)

# To set the csv filename
csvfilename = ""
for repository in args.repositories:
    csvfilename_temp = "{}".format(repository.replace("/", "-"))
    csvfilename = csvfilename + csvfilename_temp
csvfilename = csvfilename + "-issues.csv"
with open(csvfilename, "w") as csvfileout:
    csv_out = csv.writer(csvfileout)
    csv_out.writerow(
        [
            "Labels",
            "Title",
            "State",
            "Open Date",
            "Close Date",
            "URL",
            "Author",
            "Assignees",
            "Milestone",
        ]
    )
    for repository in args.repositories:
        l_url = "https://api.github.com/repos/{}/issues?state={}"
        l_url = l_url.format(repository, states)
        response = requests.get(l_url, auth=auth)
        write_issues(response, csv_out)
        get_issues_from_github_to_csv(repository, response)
csvfileout.close()
